﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Timers;
using VMS.FTS.APPPUSH.Utils;

namespace VMS.FTS.APPPUSH.LOGGER
{          
    /// <summary>
    /// VMS Logger system
    /// </summary>
    public class Logger
    {
        #region | Singleton construction |
        private static readonly Lazy<Logger> lazy =
            new Lazy<Logger>(() => new Logger());

        public static Logger Instance { get { return lazy.Value; } }
        #endregion

        #region | Contructor |
        /// <summary>
        /// Default constructor
        /// Init timer
        /// Init Log entry object
        /// </summary>
        public Logger()
        {
            // create timer with timeout
            LogTimer = new Timer(LOG_TIMEOUT);
            // auto start timer when timeout
            LogTimer.AutoReset = true;
            // callback function
            LogTimer.Elapsed += LogTimer_Elapsed;
            // start timer
            LogTimer.Start();
            // create LogEntry object to hold log
            LogEntry = new List<string>();
            // call timerfunction for first time.
            LogTimer_Elapsed(LogTimer, null);
        }

        /// <summary>
        /// Save all log entry to file
        /// Check if there is need to create new log file
        /// </summary>
        /// <param name="sender">LogTimer</param>
        /// <param name="e"></param>
        void LogTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            // check Log avaible
            if (LogEntry.Count > 0)
            {
                // create new temp log entry
                List<String> tempEntry = new List<string>();
                lock (LogEntry)
                {
                    // copy log entry
                    tempEntry.AddRange(LogEntry);
                    // clear log
                    LogEntry.Clear();
                }

                // process log file
                DateTime dt = DateTime.Now;
                String filePath = logDirectory + dt.ToString("yyyyMMdd") + ".log";
                // If log file not exist then create new one
                if (!File.Exists(filePath))
                {
                    // create log file
                    FileStream fs = File.Create(filePath);
                    // close
                    fs.Close();
                }

                // write log entry to file
                try
                {
                    StreamWriter sw = File.AppendText(filePath);
                    // write each log entry per line
                    foreach (string str in tempEntry)
                        sw.WriteLine(str);
                    // flush stream
                    sw.Flush();
                    // close stream
                    sw.Close();
                }
                catch (Exception ex)
                {
                    // print exception if error
                    Console.WriteLine(ex.Message.ToString());
                }
            }

        }
        #endregion

        #region | Methods |
        /// <summary>
        /// Append string to log file
        /// </summary>
        public void append(String source,String message, LOG_LEVEL level)
        {
            LOG_LEVEL logLevel = LOG_LEVEL.OFF;
            // Convert log level string to LOG_LEVEL enum
            switch (strLogLevel)
            {
                case "ALL":
                    logLevel = LOG_LEVEL.ALL;
                    break;

                case "ERROR":
                    logLevel = LOG_LEVEL.ERROR;
                    break;

                case "INFO":
                    logLevel = LOG_LEVEL.INFO;
                    break;
                case "DEBUG":
                    logLevel = LOG_LEVEL.DEBUG;
                    break;
                default:
                    logLevel = LOG_LEVEL.OFF;
                    break;
            }

            // check if log level > current level then add to log entry
            if (logLevel >= level)
            {
                // time stamp
                DateTime dt = DateTime.Now;
                /// create log entry
                /// Format: Date | level | source | message
                string logLv = EnumUtils.GetEnumDescription(level);
                LogEntry.Add(dt.ToString("hh:mm:ss") +
                    " | " + logLv +
                    " | " + source +
                    " | " + message);
            }
        }
        #endregion

        #region | Fields |
        /// <summary>
        /// Log level
        /// </summary>
        private String strLogLevel = String.Empty;
        public String LogLevel
        {
            get { return strLogLevel; }
            set { strLogLevel = value; }
        }

        /// <summary>
        /// Log directory
        /// </summary>
        private String logDirectory = String.Empty;
        public String LogDir
        {
            get { return logDirectory; }
            set { logDirectory = value; }
        }

        List<String> LogEntry;
        Timer LogTimer;

        const int LOG_TIMEOUT = 5000;
        #endregion
    }
}
